﻿#include"GameLib/Framework.h"
using namespace GameLib;

const char gStageData[] = "\
########\n\
# .. p #\n\
# oo   #\n\
#      #\n\
########";

const int gStageWidth = 8;
const int gStageHeight = 5;

enum Object {
	OBJ_SPACE,
	OBJ_WALL,
	OBJ_GOAL,
	OBJ_BLOCK,
	OBJ_BLOCK_ON_GOAL,
	OBJ_MAN,
	OBJ_MAN_ON_GOAL,
	OBJ_UNKNOWN,
};

void initialize(Object* state, int w, int h, const char* stageData);
void draw(const Object* state, int w, int h);
void update(Object* state, char input, int w, int h);
bool checkClear(const Object* state, int w, int y);

static Object* state = 0;

namespace GameLib {
	void Framework::update() {
		if (!state) {
			state = new Object[gStageWidth * gStageHeight];
			initialize(state, gStageWidth, gStageHeight, gStageData);
			draw(state, gStageWidth, gStageHeight);
		}
		else {
			//if (checkClear(state, gStageWidth, gStageHeight)) {
			//	cout << "Congratulation's you won." << endl;
			//	//delete[] state;
			//	state = 0;
			//}
			cout << "a:left s:right w:up z:down. command? " << endl;
			char input;
			cin >> input;
			::update(state, input, gStageWidth, gStageHeight);
			draw(state, gStageWidth, gStageHeight);
		}
	}
}

void initialize(Object* state, int width, int /*height*/, const char* stageData) {
	const char* d = stageData;
	int x = 0;
	int y = 0;
	while (*d != '\0') {
		Object t;
		switch (*d) {
		case '#': t = OBJ_WALL; break;
		case ' ': t = OBJ_SPACE; break;
		case 'o': t = OBJ_BLOCK; break;
		case 'O': t = OBJ_BLOCK_ON_GOAL; break;
		case '.': t = OBJ_GOAL; break;
		case 'p': t = OBJ_MAN; break;
		case 'P': t = OBJ_MAN_ON_GOAL; break;
		case '\n': x = 0; ++y; t = OBJ_UNKNOWN; break;
		default: t = OBJ_UNKNOWN; break;
		}
		++d;
		if (t != OBJ_UNKNOWN) {
			state[y * width + x] = t;
			++x;
		}
	}
}

void draw(const Object* state, int width, int height) {
	const char font[] = { ' ', '#', '.', 'o', 'O', 'p', 'P' };
	unsigned* vram = Framework::instance().videoMemory();
	int windowWidth = Framework::instance().width();
	for (int y = 0; y < height; y++) {
		for (int x = 0; x < width; x++) {
			Object o = state[y * width + x];
			unsigned c = 0;
			cout << font[o];
			switch (font[o]) {
			case '.': cout << '.'; c = 0x0000ff; break;
			case '#': cout << '#'; c = 0xffffff; break;
			case 'O': cout << 'O'; c = 0xff00ff; break;
			case 'P': cout << 'P'; c = 0x00ffff; break;
			case ' ': cout << ' '; c = 0x000000; break;
			case 'o': cout << 'o'; c = 0xffffff; break;
			case 'p': cout << 'p'; c = 0x00ff00; break;
			}
			for (int i = 0; i < 16; i++) {
				for (int j = 0; j < 16; j++) {
					vram[(y * 16 + i) * windowWidth + (x * 16 + j)] = c;
				}
			}
		}
		cout << endl;
	}
}

void update(Object* s, char input, int w, int h) {
	int dx = 0;
	int dy = 0;
	switch (input) {
	case 'a': dx = -1; break;
	case 's': dx = 1; break;
	case 'w': dy = -1; break;
	case 'z': dy = 1; break;
	}
	int i = -1;
	for (i = 0; i < w * h; ++i) {
		if (s[i] == OBJ_MAN || s[i] == OBJ_MAN_ON_GOAL) {
			break;
		}
	}
	int x = i % w;
	int y = i / w;

	int tx = x + dx;
	int ty = y + dy;

	if (tx < 0 || ty < 0 || tx >= w || ty >= h) {
		return;
	}

	int p = y * w + x;
	int tp = ty * w + tx;
	if (s[tp] == OBJ_SPACE || s[tp] == OBJ_GOAL) {
		s[tp] = (s[tp] == OBJ_GOAL) ? OBJ_MAN_ON_GOAL : OBJ_MAN;
		s[p] = (s[p] == OBJ_MAN_ON_GOAL) ? OBJ_GOAL : OBJ_SPACE;
	}
	else if (s[tp] == OBJ_BLOCK || s[tp] == OBJ_BLOCK_ON_GOAL) {
		int tx2 = tx + dx;
		int ty2 = ty + dy;
		if (tx2 < 0 || ty2 < 0 || tx2 >= w || ty2 >= h) {
			return;
		}
		int tp2 = (ty + dy) * w + (tx + dx);
		if (s[tp2] == OBJ_SPACE || s[tp2] == OBJ_GOAL) {
			s[tp2] = (s[tp2] == OBJ_GOAL) ? OBJ_BLOCK_ON_GOAL : OBJ_BLOCK;
			s[tp] = (s[tp] == OBJ_BLOCK_ON_GOAL) ? OBJ_MAN_ON_GOAL : OBJ_MAN;
			s[p] = (s[p] == OBJ_MAN_ON_GOAL) ? OBJ_GOAL : OBJ_SPACE;
		}
	}
}

bool checkClear(const Object* s, int width, int height) {
	for (int i = 0; i < width * height; ++i) {
		if (s[i] == OBJ_BLOCK) {
			return false;
		}
	}
	return true;
}

